package com.wunong.smart.address.domain.service.impl;

import com.wunong.smart.address.domain.UserAddressDomain;
import com.wunong.smart.address.application.context.UserAddressContext;
import com.wunong.smart.address.domain.operation.UserAddressOperationFactory;
import com.wunong.smart.address.repository.UserAddressRepository;
import com.wunong.smart.address.application.request.BaseUserAddressRequest;
import com.wunong.smart.address.application.request.DeleteUserAddressRequest;
import com.wunong.smart.address.application.request.SetDefaultUserAddressRequest;
import com.wunong.smart.address.application.request.UpdateUserAddressRequest;
import com.wunong.smart.address.domain.service.UserAddressDomainService;
import com.wunong.smart.domain.component.lock.DistributeLockSupport;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author create by zealot.zt
 */
@Slf4j
public class UserAddressDomainServiceImpl implements UserAddressDomainService {

    @Resource
    private DistributeLockSupport distributeLockSupport;

    @Resource
    private UserAddressRepository userAddressRepository;

    @Override
    public Long save(UpdateUserAddressRequest request) {
        String uniqueKey = getUniqueKey("save_user_address", request);

        return distributeLockSupport.withLock(() -> add(request), uniqueKey);
    }

    @Override
    public Void update(UpdateUserAddressRequest request) {
        String uniqueKey = getUniqueKey(request);

        distributeLockSupport.withLock(() -> operate(request), uniqueKey);
        return null;
    }

    @Override
    public Void delete(DeleteUserAddressRequest request) {
        String uniqueKey = getUniqueKey(request);

        distributeLockSupport.withLock(() -> operate(request), uniqueKey);
        return null;
    }

    @Override
    public Void setDefault(SetDefaultUserAddressRequest request) {
        String uniqueKey = getUniqueKey(request);

        distributeLockSupport.withLock(() -> operate(request), uniqueKey);
        return null;
    }

    protected String getUniqueKey(BaseUserAddressRequest request) {
        return getUniqueKey("op_user_address", request);
    }

    public String getUniqueKey(String prefix, BaseUserAddressRequest request) {
        String key = "_";

        if (Objects.nonNull(request.getId())) {
            key = key + request.getId();
        } else if (Objects.nonNull(request.getUserId())) {
            key = key + request.getUserId();
        } else {
            key = key + request.getOperator().getId();
        }

        return prefix + key;
    }

    @SuppressWarnings("unchecked")
    protected <T> T operate(BaseUserAddressRequest request) {
        UserAddressDomain domain = userAddressRepository.getByIdNonNull(request.getUserId(), request.getId());

        return (T) UserAddressOperationFactory.getOperation(request.getClass())
                .operate(UserAddressContext.of(request, domain));

    }

    @SuppressWarnings("unchecked")
    protected <T> T add(UpdateUserAddressRequest request) {
        return (T) UserAddressOperationFactory.getOperation(request.getClass())
                .operate(UserAddressContext.of(request));
    }

}
